// node class_extends_demo.js
// npx babel-node class_extends_demo.js

let _ = '';
const {log} = console;

// 子类必须在constructor方法中调用super方法，否则新建实例时会报错。这是因为子类自己的this对象，必须先通过父类的构造函数完成塑造，得到与父类同样的实例属性和方法，然后再对其进行加工，加上子类自己的实例属性和方法。如果不调用super方法，子类就得不到this对象。
let test1 = function(){
    class Point {}

    class ColorPoint extends Point {
        constructor(){}
    }

    let cp = new ColorPoint();
};
// ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
// test1();

// 因此super()在这里相当于A.prototype.constructor.call(this)。
let test2 = function(){
    class A {
        constructor(){
            log(new.target.name);
        }
    }
    class B extends A {
        constructor(){
            super();
        }
    }
    new A();
    new B();
};
// test2();

// 第二种情况，super作为对象时，在普通方法中，指向父类的原型对象；在静态方法中，指向父类。
let test3 = function(){
    class A {
        p() {
            return 2;
        }
    }
    class B extends A {
        constructor(){
            super();
            log(super.p());
        }
    }
    let b = new B();
};
// test3();

// ES6 规定，在子类普通方法中通过super调用父类的方法时，方法内部的this指向当前的子类实例。
let test4 = function(){
    class A {
        constructor() {
            this.x = 1;
        }
        print() {
            log(this.x);
        }
    }
    class B extends A {
        constructor() {
            super();
            this.x = 2;
        }
        m() {
            super.print();
        }
    }

    let b = new B();
    b.m();
};
// test4();

// 如果能清晰地表明super的数据类型，就不会报错。
let test5 = function(){
    class A {}
    class B extends A {
        constructor(){
            super();
            log(super.valueOf());
            log(super.valueOf() instanceof B);
        }
    }
    let b = new B();
};
// test5();

// 由于对象总是继承其他对象的，所以可以在任意一个对象中，使用super关键字
let test6 = function(){
    let obj = {
        toString(){
            return "MyObject: " + super.toString();
        }
    };
    _ = obj.toString();
    log(_);
};
// test6();

let test7 = function(){
    class A {}
    class B extends A {}

    _ = B.__proto__ === A
    log(_);

    _ = B.prototype.__proto__ === A.prototype;
    log(_);
};
// test7();









